<!DOCTYPE html>
<html>
<head>
    <title>Wave Propagation Diagram</title>
</head>
<body>
    <canvas id="physicsCanvas" width="500" height="500" style="border:1px solid #d3d3d3;"></canvas>
    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        // --- Style and Config ---
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';
        ctx.lineWidth = 2;
        const mainFont = 'italic 22px Times New Roman';
        const angleFont = '24px Times New Roman';
        const subscriptFont = 'italic 16px Times New Roman';

        // --- Geometry Config ---
        const origin = { x: 250, y: 300 };
        const gamma_deg = 30;
        const gamma_rad = gamma_deg * Math.PI / 180;
        // The vector N is at angle gamma with the z-axis. 
        // In a standard math coordinate system, this is angle gamma.
        // In canvas, where y is inverted, the angle from the positive x-axis is -gamma.
        const drawAngle = -gamma_rad; 

        // --- Helper Functions ---
        function drawArrow(ctx, x1, y1, x2, y2) {
            const headlen = 10;
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
            const angle = Math.atan2(y2 - y1, x2 - x1);
            ctx.beginPath();
            ctx.moveTo(x2, y2);
            ctx.lineTo(x2 - headlen * Math.cos(angle - Math.PI / 6), y2 - headlen * Math.sin(angle - Math.PI / 6));
            ctx.lineTo(x2 - headlen * Math.cos(angle + Math.PI / 6), y2 - headlen * Math.sin(angle + Math.PI / 6));
            ctx.closePath();
            ctx.fill();
        }

        function drawVectorLabel(ctx, text, x, y, subscript = '') {
            ctx.font = mainFont;
            const metrics = ctx.measureText(text);
            ctx.fillText(text, x, y);

            const arrowY = y - 22;
            const arrowX = x;
            ctx.save();
            ctx.lineWidth = 1.5;
            ctx.beginPath();
            ctx.moveTo(arrowX, arrowY);
            ctx.lineTo(arrowX + metrics.width, arrowY);
            ctx.lineTo(arrowX + metrics.width - 6, arrowY - 3);
            ctx.moveTo(arrowX + metrics.width, arrowY);
            ctx.lineTo(arrowX + metrics.width - 6, arrowY + 3);
            ctx.stroke();
            ctx.restore();

            if (subscript) {
                ctx.font = subscriptFont;
                ctx.fillText(subscript, x + metrics.width, y + 6);
            }
        }

        // --- Drawing ---

        // 1. Axes
        ctx.font = mainFont;
        drawArrow(ctx, 50, origin.y, 480, origin.y); // z-axis
        ctx.fillText('z', 485, origin.y + 8);
        drawArrow(ctx, origin.x, 450, origin.x, 50); // x-axis
        ctx.fillText('x', origin.x + 10, 55);

        // 2. Vectors N and v
        const L_N = 180;
        const L_v = 110;
        const N_end = { x: origin.x + L_N * Math.cos(drawAngle), y: origin.y + L_N * Math.sin(drawAngle) };
        const v_end = { x: origin.x + L_v * Math.cos(drawAngle), y: origin.y + L_v * Math.sin(drawAngle) };
        
        // Draw the main vector line and arrow for N
        drawArrow(ctx, origin.x, origin.y, N_end.x, N_end.y);
        // Draw the arrowhead for v on the same line
        drawArrow(ctx, v_end.x - 10 * Math.cos(drawAngle), v_end.y - 10 * Math.sin(drawAngle), v_end.x, v_end.y);

        // 3. Vector v_x
        const L_vx = 80;
        const vx_end = { x: origin.x, y: origin.y - L_vx };
        drawArrow(ctx, origin.x, origin.y, vx_end.x, vx_end.y);

        // 4. Wavefronts
        // Wavefronts are perpendicular to N.
        // Slope of N is tan(drawAngle) = -tan(gamma_rad).
        // Slope of wavefronts in math coords is cot(gamma_rad).
        // Slope in canvas coords is -cot(gamma_rad).
        const wavefront_slope_canvas = -1 / Math.tan(gamma_rad);
        
        function drawWavefront(center_x, center_y, length) {
            const angle = Math.atan(wavefront_slope_canvas);
            const dx = length * Math.cos(angle);
            const dy = length * Math.sin(angle);
            ctx.beginPath();
            ctx.moveTo(center_x - dx, center_y - dy);
            ctx.lineTo(center_x + dx, center_y + dy);
            ctx.stroke();
        }

        // Wavefront 1 (through origin)
        drawWavefront(origin.x, origin.y, 140);
        
        // Wavefront 2 (offset along N)
        const offset_dist = 40;
        const offset_point = {
            x: origin.x + offset_dist * Math.cos(drawAngle),
            y: origin.y + offset_dist * Math.sin(drawAngle)
        };
        drawWavefront(offset_point.x, offset_point.y, 140);


        // 5. Angle gamma
        // The angle is shown in the 3rd quadrant, as vertically opposite to the actual angle.
        const angle_line_len = 100;
        const angle_line_end = {
            x: origin.x - angle_line_len * Math.cos(gamma_rad),
            y: origin.y + angle_line_len * Math.sin(gamma_rad)
        };
        ctx.beginPath();
        ctx.moveTo(origin.x, origin.y);
        ctx.lineTo(angle_line_end.x, angle_line_end.y);
        ctx.stroke();

        const arc_radius = 45;
        ctx.beginPath();
        ctx.arc(origin.x, origin.y, arc_radius, Math.PI, Math.PI + gamma_rad);
        ctx.stroke();

        // 6. Labels
        drawVectorLabel(ctx, 'N', N_end.x, N_end.y);
        drawVectorLabel(ctx, 'v', v_end.x - 45, v_end.y - 5);
        drawVectorLabel(ctx, 'v', origin.x - 45, origin.y - L_vx - 5, 'x');

        ctx.font = angleFont;
        ctx.fillText('γ', origin.x - 70, origin.y + 35);
    </script>
</body>
</html>